package com.zjun.strategy;

import com.zjun.ApplicationContextHolder;
import com.zjun.exception.ServiceException;
import com.zjun.init.ApplicationInitializingEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;

public class AbstractExecutegyChoose implements ApplicationListener<ApplicationInitializingEvent> {
    /**
     * 执行策略集合
     */
    private final Map<String,AbstractExecuteStrategy> abstractExecuteStrategyMap = new HashMap<>();

    /**
     * 依照mark寻找具体执行策略
     * @param mark 策略标识
     * @param predicateFlag 是否开启解析标识
     * @return 具体执行策略
     */
    public AbstractExecuteStrategy choose(String mark,Boolean predicateFlag){
        if (predicateFlag != null && predicateFlag){
            return abstractExecuteStrategyMap.values().stream()
                    .filter(each -> Pattern.compile(each.patternMatchMark()).matcher(mark).matches())
                    .findFirst()
                    .orElseThrow(()-> new ServiceException("策略未定义"));
        }
        return Optional.ofNullable(abstractExecuteStrategyMap.get(mark))
                .orElseThrow(()-> new ServiceException("[AbstractExecutegyChoose]"+String.format("[%s] 策略未定义",mark)));
    }

    /**
     * 查询某个具体的策略，并执行
     * @param mark 策略标识
     * @param requestParam 执行策略入参
     * @param <REQUEST> 执行策略入参泛型
     */
    public <REQUEST> void chooseAndExecute(String mark,REQUEST requestParam){
        AbstractExecuteStrategy choose = choose(mark, false);
        choose.execute(requestParam);

    }

    /**
     *  根据 mark 查询具体策略并执行
     * @param mark 策略标识
     * @param requestParam 执行策略入参
     * @param predicateFlag 匹配范解析标识
     * @param <REQUEST> 执行策略入参范型
     */
    public <REQUEST> void chooseAndExecute(String mark,REQUEST requestParam,Boolean predicateFlag){
        AbstractExecuteStrategy choose = choose(mark, predicateFlag);
        choose.execute(requestParam);
    }

    public <REQUEST,RESPONSE> RESPONSE chooseAndExecuteResponse(String mark,REQUEST requestParam){
        AbstractExecuteStrategy choose = choose(mark, null);
        return (RESPONSE) choose.executeResponse(requestParam);
    }


    @Override
    public void onApplicationEvent(ApplicationInitializingEvent event) {
        Map<String, AbstractExecuteStrategy> actual = ApplicationContextHolder.getBeansOfType(AbstractExecuteStrategy.class);
        actual.forEach((beanName, bean) -> {
            AbstractExecuteStrategy beanExist = abstractExecuteStrategyMap.get(bean.mark());
            if (beanExist != null) {
                throw new ServiceException("[AbstractExecutegyChoose]"+String.format("[%s] Duplicate execution policy", bean.mark()));
            }
            abstractExecuteStrategyMap.put(bean.mark(), bean);
        });
    }
}
